package com.aaa.test.config;


import cn.hutool.json.JSONUtil;


import com.aaa.test.filter.JwtVerifyFilter;
import com.aaa.test.util.JWTUtil;
import com.aaa.test.util.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.io.PrintWriter;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * @ClassName MySpringSecurityConfig
 * @Description TODO
 * @Aythor WYX
 * @Date 2022/11/2 17:00
 * Version 1.0
 **/
@Configuration
public class MySpringSecurityConfig {

    @Autowired
    private JwtVerifyFilter jwtVerifyFilter;

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    //这里的map将权限和信息分开存入username，authorities 在这个加密后的令牌中，不存在因为第三方服务停用
    //导致的session不同,这种加密方式，相当于用户第一次访问就去获取token，拿着这个token去访问服务，服务只需要判断你有没有token
    //而这个token中可以存放多种信息，比如密码，权限，角色 既然相当于对用户的信息进行了加密，而这个加密规则服务器知道，且用户拿到
    //的token 是加密过后的，不会又泄露风险
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http)throws Exception{
        http.addFilterBefore(jwtVerifyFilter, UsernamePasswordAuthenticationFilter.class);
        http.exceptionHandling().accessDeniedHandler(accessDeniedHandler());

        http.formLogin()
                //.loginPage("/login.html")
                .loginProcessingUrl("/login")
                //.successForwardUrl("/success")
                .successHandler(successHandler())

                //声明登陆成功后需要进行的任务，而不是向之前，登陆成功后发出success请求
                .permitAll();
        //允许跨域
        http.cors();
        http.csrf().disable();

        http.authorizeHttpRequests().anyRequest().authenticated();
        return http.build();
    }
    private AuthenticationSuccessHandler successHandler(){
        return (request, response, authentication) -> {
            response.setContentType("application/json;charset=utf-8");
            PrintWriter writer = response.getWriter();

            //生成token 按照用户名和用户具有的权限。
            Map<String,Object> map=new HashMap<>();
            User principal = (User) authentication.getPrincipal();
            //获取当前用户的名称
            String username = principal.getUsername();
            //获取当前用户具有的权限
            Collection<GrantedAuthority> authorities = principal.getAuthorities();
            //authorities 这个对象中放了权限比如角色集合，权限集合
            //stream流把集合中原生的类型转化为另一张类型
            List<String> list = authorities.stream().map(item -> item.getAuthority()).collect(Collectors.toList());
            map.put("username",username);
            map.put("authorities",list);
            String token = JWTUtil.createJWT(map);

            //封装到公共json对象中
            Result result=new Result(200,"登录成功",token);
            String json = JSONUtil.toJsonStr(result);
            writer.print(json);
            //刷新token
            writer.flush();
            //关闭通道
            writer.close();

        };
    }
    private AccessDeniedHandler accessDeniedHandler(){
        return ((request, response, accessDeniedException) ->{
            response.setContentType("application/jason;charts=utf-8");

            PrintWriter writer = response.getWriter();
            Map<String, Object> map = new HashMap<>();
            map.put("code", 403);
            map.put("msg", "权限不足");
            map.put("data", "数据");
            String jsonStr = JSONUtil.toJsonStr(map);
            writer.print(jsonStr);
            writer.flush();
            writer.close();
        } );
    }
}
